#ifndef PARSER_H
#define PARSER_H

#include "compiler/lexer.h"
#include <memory>
#include <vector>
#include <stdexcept>

namespace AST {
    class Node {
    public:
        int line;
        int column;

        Node(int l = 0, int c = 0) : line(l), column(c) {}
        virtual ~Node() = default;
        virtual std::string toString() const = 0;
    };

    class Expression : public Node {
    public:
        Expression(int line = 0, int column = 0) : Node(line, column) {}
    };

    class BinaryExpression : public Expression {
    public:
        std::unique_ptr<Expression> left;
        std::string op;
        std::unique_ptr<Expression> right;

        BinaryExpression(std::unique_ptr<Expression> l, const std::string& o, std::unique_ptr<Expression> r, int line = 0, int column = 0)
            : Expression(line, column), left(std::move(l)), op(o), right(std::move(r)) {
        }

        std::string toString() const override {
            return "(" + left->toString() + " " + op + " " + right->toString() + ")";
        }
    };

    class Literal : public Expression {
    public:
        std::string value;
        TokenType type;

        Literal(const std::string& v, TokenType t, int line = 0, int column = 0)
            : Expression(line, column), value(v), type(t) {}

        std::string toString() const override {
            return value;
        }
    };

    class Identifier : public Expression {
    public:
        std::string name;

        Identifier(const std::string& n, int line = 0, int column = 0)
            : Expression(line, column), name(n) {}

        std::string toString() const override {
            return name;
        }
    };

    class Statement : public Node {
    public:
        Statement(int line = 0, int column = 0) : Node(line, column) {}
    };

    class CreateTableStmt : public Statement {
    public:
        std::string tableName;
        std::vector<std::pair<std::string, std::string>> columns;

        CreateTableStmt(int line = 0, int column = 0) : Statement(line, column) {}

        std::string toString() const override {
            std::string result = "CREATE TABLE " + tableName + " (";
            for (size_t i = 0; i < columns.size(); ++i) {
                if (i > 0) result += ", ";
                result += columns[i].first + " " + columns[i].second;
            }
            result += ")";
            return result;
        }
    };

    class InsertStmt : public Statement {
    public:
        std::string tableName;
        std::vector<std::string> columns;
        std::vector<std::unique_ptr<Expression>> values;

        InsertStmt(int line = 0, int column = 0) : Statement(line, column) {}

        std::string toString() const override {
            std::string result = "INSERT INTO " + tableName;
            if (!columns.empty()) {
                result += " (";
                for (size_t i = 0; i < columns.size(); ++i) {
                    if (i > 0) result += ", ";
                    result += columns[i];
                }
                result += ")";
            }
            result += " VALUES (";
            for (size_t i = 0; i < values.size(); ++i) {
                if (i > 0) result += ", ";
                result += values[i]->toString();
            }
            result += ")";
            return result;
        }
    };

    class SelectStmt : public Statement {
    public:
        std::vector<std::string> columns;
        std::string tableName;
        std::unique_ptr<Expression> whereClause;

        SelectStmt(int line = 0, int column = 0) : Statement(line, column) {}

        std::string toString() const override {
            std::string result = "SELECT ";
            for (size_t i = 0; i < columns.size(); ++i) {
                if (i > 0) result += ", ";
                result += columns[i];
            }
            result += " FROM " + tableName;
            if (whereClause) {
                result += " WHERE " + whereClause->toString();
            }
            return result;
        }
    };

    class DeleteStmt : public Statement {
    public:
        std::string tableName;
        std::unique_ptr<Expression> whereClause;

        DeleteStmt(int line = 0, int column = 0) : Statement(line, column) {}

        std::string toString() const override {
            std::string result = "DELETE FROM " + tableName;
            if (whereClause) {
                result += " WHERE " + whereClause->toString();
            }
            return result;
        }
    };    
    // Add UpdateStmt class definition after DeleteStmt
    class UpdateStmt : public Statement {
    public:
        std::string tableName;
        std::vector<std::pair<std::string, std::unique_ptr<Expression>>> columnValues;
        std::unique_ptr<Expression> whereClause;
    
        std::string toString() const override {
            std::string result = "UPDATE " + tableName + " SET ";
            for (size_t i = 0; i < columnValues.size(); ++i) {
                if (i > 0) result += ", ";
                result += columnValues[i].first + " = " + columnValues[i].second->toString();
            }
            if (whereClause) {
                result += " WHERE " + whereClause->toString();
            }
            return result;
        }
    };
}

class ParserError : public std::runtime_error {
public:
    ParserError(const std::string& msg, int line, int col)
        : std::runtime_error("[SYNTAX_ERROR, " + std::to_string(line) + ", " + std::to_string(col) + "] " + msg) {}
};

class Parser {
public:
    Parser(const std::vector<Token>& tokens);
    std::unique_ptr<AST::Statement> parse();
    std::vector<std::unique_ptr<AST::Statement>> parseMultipleStatements();

private:
    std::unique_ptr<AST::Statement> parseStatement();
    std::unique_ptr<AST::CreateTableStmt> parseCreateTable();
    std::unique_ptr<AST::InsertStmt> parseInsert();
    std::unique_ptr<AST::SelectStmt> parseSelect();
    std::unique_ptr<AST::DeleteStmt> parseDelete();
    std::unique_ptr<AST::UpdateStmt> parseUpdate();
    std::unique_ptr<AST::Expression> parseExpression();
    std::unique_ptr<AST::Expression> parseAndExpression();
    std::unique_ptr<AST::Expression> parseComparison();
    std::unique_ptr<AST::Expression> parsePrimary();

    Token peek() const;
    Token advance();
    bool match(TokenType type);
    bool match(TokenType type, const std::string& value);
    Token expect(TokenType type, const std::string& message);
    Token expect(TokenType type, const std::string& value, const std::string& message);
    bool check(TokenType type) const;
    bool check(TokenType type, const std::string& value) const;
    // Helper function: Case-insensitive string comparison
    bool equalsIgnoreCase(const std::string& a, const std::string& b) const;

    std::vector<Token> tokens;
    size_t current;
};

#endif // PARSER_H
